#include "BellmanFordTest.h"

namespace zbp
{
	using namespace boost;

double bellman_ford_SimpleGraph_test(int source_vertex, SimpleGraph graph, bool display)
{
	vector<int> d, p;

	clock_t ticks = clock();

	bool result = graph.bellman_ford_initialized(source_vertex, d, p);

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "SimpleGraph class: bellman_ford method for node " << source_vertex << endl << endl;

		if (result)
			display_vector(d, std::numeric_limits<int>::max());
		else
			cout << "Negative weight found." << endl;

		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double bellman_ford_boost_test(int source_vertex, BoostEdge* edge_array, int* weights, int nodes_count, int edges_count, bool display)
{	   	  	  	  	  	  	  	  
	typedef adjacency_list < vecS, vecS, directedS,
		no_property, EdgeProperties> Graph;
	#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
		// VC++ can't handle the iterator constructor
		Graph g(nodes_count);
		for (std::size_t j = 0; j < n_edges; ++j)
			add_edge(edge_array[j].first, edge_array[j].second, g);
	#else
		Graph g(edge_array, edge_array + edges_count, nodes_count);
	#endif
	graph_traits < Graph >::edge_iterator ei, ei_end;
	property_map<Graph, int EdgeProperties::*>::type 
	weight_pmap = get(&EdgeProperties::weight, g);
	int i = 0;
	for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei, ++i)
		weight_pmap[*ei] = weights[i];

	std::vector<int> distance(nodes_count, (std::numeric_limits < short >::max)());
	std::vector<std::size_t> parent(nodes_count);
	for (i = 0; i < nodes_count; ++i)
		parent[i] = i;

	distance[source_vertex] = 0;

	clock_t ticks = clock();

	#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
		bool result = bellman_ford_shortest_paths
			(g, int(nodes_count), weight_pmap, &parent[0], &distance[0], 
			closed_plus<int>(), std::less<int>(), default_bellman_visitor());
	#else
		bool result = bellman_ford_shortest_paths
			(g, int (nodes_count), weight_map(weight_pmap).distance_map(&distance[0]).
			predecessor_map(&parent[0]));
	#endif	 

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "Boost: bellman_ford_shortest_paths function for node " << source_vertex << endl << endl;

		if (result)
		{
			display_vector(distance, std::numeric_limits<int>::max());	
		}
		else
		{
			cout << "Negative weight found." << endl;
		}

		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double n_bellman_ford_SimpleGraph_test(SimpleGraph graph, bool display)
{
	int n = graph.get_nodes_count();
	DistanceMatrix<int> d(n, 0);
	DistanceMatrix<int> p(n, 0);

	bool result = true;
	clock_t ticks = clock();

	for (int i = 0; i < n && result; i++)
	{
		result = graph.bellman_ford_initialized(i, d[i], p[i]);
	}

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "SimpleGraph class: bellman_ford method for all nodes" << endl << endl;

		if (result)
			d.display();
		else
			cout << "Negative weight found." << endl;

		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double n_bellman_ford_CompleteGraph_test(CompleteGraph<int> graph, bool display)
{
	int n = graph.get_nodes_count();
	DistanceMatrix<int> d(n, 0);
	DistanceMatrix<int> p(n, 0);

	clock_t ticks = clock();

	bool result = true;
	for (int i = 0; i < n && result; i++)
	{
		result = graph.bellman_ford_initialized(i, d[i], p[i]);
	}

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "SimpleGraph class: bellman_ford method for all nodes" << endl << endl;

		if (result)
			d.display();
		else
			cout << "Negative weight found." << endl;

		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

double n_bellman_ford_boost_test(BoostEdge* edge_array, int* weights, int nodes_count, int edges_count, bool display)
{
	typedef adjacency_list < vecS, vecS, directedS,
		no_property, EdgeProperties> Graph;
	#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
		// VC++ can't handle the iterator constructor
		Graph g(nodes_count);
		for (std::size_t j = 0; j < n_edges; ++j)
			add_edge(edge_array[j].first, edge_array[j].second, g);
	#else
		Graph g(edge_array, edge_array + edges_count, nodes_count);
	#endif
	graph_traits < Graph >::edge_iterator ei, ei_end;
	property_map<Graph, int EdgeProperties::*>::type 
	weight_pmap = get(&EdgeProperties::weight, g);
	int i = 0;
	for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei, ++i)
		weight_pmap[*ei] = weights[i];

	std::vector<int> distance(nodes_count, (std::numeric_limits < short >::max)());
	std::vector<std::size_t> parent(nodes_count);
	for (i = 0; i < nodes_count; ++i)
		parent[i] = i;

	DistanceMatrix<int> d(nodes_count, nodes_count);

	bool result = true;

	clock_t ticks = clock();

	for (int i = 0; i < nodes_count && result; i++)
	{
		distance[i] = 0;

		#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
			bool result = bellman_ford_shortest_paths
				(g, int(nodes_count), weight_pmap, &parent[0], &distance[0], 
				closed_plus<int>(), std::less<int>(), default_bellman_visitor());
		#else
			bool result = bellman_ford_shortest_paths
				(g, int (nodes_count), weight_map(weight_pmap).distance_map(&d[i][0]).
				predecessor_map(&parent[0]));
		#endif	
	}

	ticks = clock() - ticks;	
	double msec = (double)ticks / CLOCKS_PER_SEC * 1000;

	if (display)
	{
		cout << "Boost: bellman_ford_shortest_paths function for all nodes" << endl << endl;

		if (result)
		{
			d.display();
		}
		else
		{
			cout << "Negative weight found." << endl;
		}

		cout << "Time in ms: " << msec << endl << endl;
	}

	return msec;
}

void bellman_ford_tests_run(SimpleGraph simple_graph, 
					        BoostEdge* boost_edges, 
					        int* boost_weights,
					        int nodes_count, int edges_count,
						    int source_vertex)
{
	bellman_ford_SimpleGraph_test(source_vertex, simple_graph, true);
	bellman_ford_boost_test(source_vertex, boost_edges, boost_weights, nodes_count, edges_count, true);

	n_bellman_ford_SimpleGraph_test(simple_graph, true);
	n_bellman_ford_boost_test(boost_edges, boost_weights, nodes_count, edges_count, true);
}

}